package com.leo.util.http;

import java.io.BufferedReader;

import java.io.IOException;
import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


import com.alibaba.fastjson.JSON;
import com.leo.util.http.builder.HttpClientBuilder;
import com.leo.util.http.common.HttpClientConstans;
import com.leo.util.http.common.Utils;
import org.apache.commons.codec.Charsets;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


/**
 * @author liusl
 * @date 2019/3/15-14:16
 */
public class HttpHelper {
    /**
     * post请求json数据
     *
     * @param url       连接地址
     * @param jsonParam json
     * @return String
     */
    public static String httpPostJson(String url, String jsonParam) {
        return httpPostJson(url, jsonParam, String.class);
    }

    public static <T> T httpPostJson(String url, String jsonParam, Class<T> tClass) {
        // 创建post请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
        StringEntity entity = new StringEntity(jsonParam, Charsets.UTF_8);
        httpPost.setEntity(entity);
        String res = getResult(httpPost, false);
        if (String.class == tClass) {
            return (T) res;
        } else {
            return JSON.parseObject(res, tClass);
        }

    }

    public static String post(String url, Map<String, Object> params) {
        return post(url, params, (Map<String, Object>) null);
    }

    public static <T> T post(String url, Map<String, Object> params, Class<T> tClass) {
        return post(url, params, null, tClass);
    }

    public static String post(String url, Map<String, Object> params, Map<String, Object> headers) {
        return post(url, params, headers, String.class);
    }


    public static <T> T post(String url, Map<String, Object> params, Map<String, Object> headers, Class<T> tClass) {
        return post(url, params, headers, false, tClass);
    }

    public static <T> T post(String url, Map<String, Object> params, Map<String, Object> headers, boolean isStream, Class<T> tClass) {
        HttpPost httpPost = new HttpPost(url);
        // 添加请求头信息
        if (null != headers) {
            for (Map.Entry<String, Object> entry : headers.entrySet()) {
                httpPost.addHeader(entry.getKey(), entry.getValue().toString());
            }
        }
        // 添加请求参数信息
        if (null != params) {
            httpPost.setEntity(new UrlEncodedFormEntity(covertParams2NVPS(params), Charsets.UTF_8));
        }
        return buildResult(getResult(httpPost, isStream), tClass);
    }
    public static String get(String url) {
        return get(url, null, (Map<String, Object>) null);
    }

    public static<T> T get(String url,Class<T> tClass) {
        return get(url, null, (Map<String, Object>) null,tClass);
    }

    public static String get(String url, Map<String, Object> params) {
        return get(url, params, (Map<String, Object>) null);
    }

    public static <T> T get(String url, Map<String, Object> params, Class<T> tClass) {
        return get(url, params, null, tClass);
    }

    public static String get(String url, Map<String, Object> params, Map<String, Object> headers) {
        return get(url, params, headers, String.class);
    }


    public static <T> T get(String url, Map<String, Object> params, Map<String, Object> headers, Class<T> tClass) {
        return get(url, params, headers, false, tClass);
    }

    public static <T> T get(String url, Map<String, Object> params, Map<String, Object> headers, boolean isStream, Class<T> tClass) {

        // 添加请求参数信息
        if (null != params) {
            url += Utils.buildParas(url, params);
        }

        HttpGet httpGet = new HttpGet(url);
        // 添加请求头信息
        if (null != headers) {
            for (Map.Entry<String, Object> entry : headers.entrySet()) {
                httpGet.addHeader(entry.getKey(), entry.getValue().toString());
            }
        }
        return buildResult(getResult(httpGet, isStream), tClass);
    }

    private static <T> T buildResult(String result, Class<T> tClass) {
        T t;
        if (tClass == String.class) {
            t = (T) result;
        } else {
            t = JSON.parseObject(result, tClass);
        }
        return t;
    }

    private static String getResult(HttpRequestBase httpRequest, boolean isStream) {
        // 响应结果
        StringBuilder sb = null;
        CloseableHttpResponse response = null;
        try {
            // 获取连接客户端
            CloseableHttpClient httpClient = HttpClientBuilder.getInstance(httpRequest.getURI().toURL().toString());
            // 发起请求
            response = httpClient.execute(httpRequest);

            int respCode = response.getStatusLine().getStatusCode();
            // 如果是重定向
            if (HttpStatus.SC_MOVED_TEMPORARILY == respCode) {
                String locationUrl = response.getLastHeader("Location").getValue();
                return getResult(new HttpPost(locationUrl), isStream);
            }
            // 正确响应
            if (HttpStatus.SC_OK == respCode) {
                // 获得响应实体
                HttpEntity entity = response.getEntity();
                sb = new StringBuilder();
                // 如果是以流的形式获取
                if (isStream) {
                    BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent(), Charsets.UTF_8));
                    String len;
                    while ((len = br.readLine()) != null) {
                        sb.append(len);
                    }
                } else {
                    sb.append(EntityUtils.toString(entity, Charsets.UTF_8));
                    if (sb.length() < 1) {
                        sb.append("-1");
                    }
                }
            }
        } catch (ConnectionPoolTimeoutException e) {
            System.err.println("从连接池获取连接超时!!!");
            e.printStackTrace();
        } catch (SocketTimeoutException e) {
            System.err.println("响应超时");
            e.printStackTrace();
        } catch (ConnectTimeoutException e) {
            System.err.println("请求超时");
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            System.err.println("http协议错误");
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            System.err.println("不支持的字符编码");
            e.printStackTrace();
        } catch (UnsupportedOperationException e) {
            System.err.println("不支持的请求操作");
            e.printStackTrace();
        } catch (ParseException e) {
            System.err.println("解析错误");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("IO错误");
            e.printStackTrace();
        } finally {
            httpRequest.releaseConnection();
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.err.println("关闭响应连接出错");
                    e.printStackTrace();
                }
            }

        }
        return sb == null ? HttpClientConstans.RESULT : ("".equals(sb.toString().trim()) ? "-1" : sb.toString());
    }

    /**
     * Map转换成NameValuePair List集合
     *
     * @param params map
     * @return NameValuePair List集合
     */
    private static List<NameValuePair> covertParams2NVPS(Map<String, Object> params) {

        List<NameValuePair> paramList = new LinkedList<>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
        }

        return paramList;

    }

}
